package com.sneaker.shower.config.socket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sneaker.shower.socket.Channel;
import com.sneaker.shower.socket.LifeCycle;
import com.sneaker.shower.socket.common.PSWsRequest;
import com.sneaker.shower.socket.repository.ChannelRepository;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Collection;

/**
 * <h1>WsHandler</h1>
 * <pre>
 * @Description
 * </pre>
 *
 * @Author lopo
 * @Date 2018/10/19
 */
public class WsHandler extends TextWebSocketHandler {
    private Logger logger = LoggerFactory.getLogger(WsHandler.class);
    private ChannelRepository channelRepository;
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static ChannelBuilder channelBuilder;

    public WsHandler(ChannelRepository channelRepository) {
        this.channelRepository = channelRepository;
        if (channelBuilder == null) {
            channelBuilder = new DefaultChannelBuilder();
        }
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
        Collection<Channel> channels = channelRepository.peek((e) -> StringUtils.equals(session.getId(), e.getId().toString()));
        if (!channels.isEmpty()) {
            channels.forEach((e) -> {
                e.check();
                logger.info("{} recevied pong and ack ping", e.sign());
            });
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
        String content = message.getPayload();
        Collection<Channel> channels = channelRepository.peek((e) -> StringUtils.equals(session.getId(), e.getId().toString()));
        if (channels.isEmpty()) {
            try {
                PSWsRequest request = objectMapper.readValue(content, PSWsRequest.class);
                Channel channel = channelBuilder.buildChannel(request, session);
                channel.doAuth(request, null);
            } catch (Exception e) {
                logger.error("~",e);
            }
        } else if (channels.size() > 1) {
            Channel channel = channels.stream().findFirst().get();
            channels.remove(channel);
            channels.forEach(LifeCycle::broken);
        }
        logger.info("recevied request : {} ,{}", message.getPayload(), session.getId());
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
        logger.error("session err: ", exception);
        afterConnectionClosed(session, CloseStatus.SERVER_ERROR);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        logger.info(session.getId() + " -----closed " + status.toString());
        super.afterConnectionClosed(session, status);
        Collection<Channel> channels = channelRepository.peek((e) -> StringUtils.equals(session.getId(), e.getId().toString()));
        if (channels != null && !channels.isEmpty()) {
            channels.forEach(LifeCycle::broken);
        }
    }
}
